/*
                  Snake Class Implementation
*/
#include "Snake.h"

Snake::Snake()
{
    iDirection = UP;
    bMoving = false;
    iWidth = 0;
    iHeight = 0;
    iSpeed = 200;
}

Snake::~Snake()
{
    for (int i = 0; i < Body.size(); i++)
    {
        delete Body.at(i);
    }

    Body.clear();

    SDL_FreeSurface(Node);
}

int Snake::Initialise(Point Position, int iNewWidth, int iNewHeight, int iNewDirection, int iSize)
{
    iWidth = iNewWidth;
    iHeight = iNewHeight;
    iDirection = iNewDirection;
    bMoving = true;

    iTimePassed = 0;

    // Create the head of the snake
    Body.push_back(new BodyNode(HEAD, Point(Position.x, Position.y)));

    int iStartSize = (iSize < 3) ? 3 : iSize;

    // Grow it to the starting size
    for (int i = 1; i < iStartSize; i++)
    {
        NodeType Type = BODY;

        if (i == iStartSize - 1)
        {
            Type = TAIL;
        }

        Body.push_back(new BodyNode(Type, Point(Position.x, Position.y)));
    }

    Node = OptimiseAlphaSurface(IMG_Load("data//sprites//bodies//0.png"));
}

int Snake::Reset(Point Position, int iNewDirection, int iSize)
{
    for (int i = 0; i < Body.size(); i++)
    {
        delete Body.at(i);
    }

    Body.clear();

    Initialise(Position, iWidth, iHeight, iNewDirection, iSize);
}

void Snake::AddSection()
{
    // Has to have at least a head node
    if (Body.size() < 1) { return; }

    Point Position = Body.back()->Position;

    // Put the new node behind the snake depending on movement direction
    switch (iDirection)
    {
        case UP:
            Position.y += iHeight;
        break;

        case DOWN:
            Position.y -= iHeight;
        break;

        case LEFT:
            Position.x += iWidth;
        break;

        case RIGHT:
            Position.x -= iWidth;
        break;
    }

    // Switch the old tail to a body node unless the old node is a head
    if (Body.back()->Type == TAIL)
    {
        Body.back()->Type = BODY;
    }

    // Add the new tail node
    Body.push_back(new BodyNode(TAIL, Point(Position.x, Position.y)));
}

void Snake::Move(Map& currentMap)
{
    // Minimum size is 3
    if (Body.size() < 3) { return; }

    // Temporary node pointer
    BodyNode *tNode = NULL;

    Point Position = Body.front()->Position;

    // Find the new head's position
    /*switch (iDirection)
    {
        case UP:
            Position.y -= iHeight;
        break;

        case DOWN:
            Position.y += iHeight;
        break;

        case LEFT:
            Position.x -= iWidth;
        break;

        case RIGHT:
            Position.x += iWidth;
        break;
    }*/

    // Change the old head to a body node
    Body.front()->Type = BODY;

    // Insert the old tail at the head of the snake
    Body.insert(Body.begin(), Body.back());

    // Remove the old tail node
    Body.pop_back();

    // The old tail is now the head node
    Body.front()->Type = HEAD;

    // Assign a new tail
    Body.back()->Type = TAIL;

    // Set the new position for the new head
    Body.front()->Position = currentMap.GetPlayerNextPosition(Position, iDirection);
}

void Snake::Draw(SDL_Surface *surface)
{
    SDL_Rect dstRect;

    for (int i = (Body.size() - 1); i >= 0; i--)
    {
        dstRect.x = (int)Body.at(i)->Position.x;
        dstRect.y = (int)Body.at(i)->Position.y;

        SDL_BlitSurface(Node, NULL, surface, &dstRect);
    }
}

void Snake::setDirection(int iNewDirection)
{
    iDirection = iNewDirection;
}

int Snake::getDirection()
{
    return iDirection;
}

int Snake::getSize()
{
    return Body.size();
}

int Snake::getHeight()
{
    return iHeight;
}

int Snake::getWidth()
{
    return iWidth;
}

Point Snake::getPosition()
{
    if (Body.size() <= 0) { return Point(0, 0); }

    return Body.front()->Position;
}

int Snake::getSpeed()
{
    return iSpeed;
}

void Snake::setSpeed(const int& iNewSpeed)
{
    iSpeed = iNewSpeed;
}

bool Snake::CanMove(const int& iFrameTime)
{
    iTimePassed += iFrameTime;

    if (iTimePassed >= iSpeed)
    {
        iTimePassed -= iSpeed;

        return true;
    }
}
